#include "ClefPublique.h"

ClefPublique * ClefPubliqueGenerer()
{
    ClefPublique * clef;
    ClefPubliqueInitialiser(&clef);
    /* On génère deux nombres premiers: p1 et p2 */
    mpz_t p1;
    mpz_t p2;
    mpz_t c1;
    mpz_t c2;
    mpz_init(p1);
    mpz_init(p2);
    mpz_init(c1);
    mpz_init(c2);

    mpz_t taille1;
    mpz_t taille2;
    mpz_init(taille1);
    mpz_init(taille2);

//    mpz_t temps;
//    mpz_init_set_ui(temps, (unsigned long int)time(NULL));
//    mpz_mul_ui(taille1, temps, 54);
//    mpz_mul_ui(taille2,temps, 12);

    unsigned long int l1;
    unsigned long int l2;
//    l1=mpz_get_ui(taille1);
//    l2=mpz_get_ui(taille2);

    l1=time(NULL)/1603291;
    l2=time(NULL)/3528412;

    mpz_urandomb(c1, state, l1);
    mpz_urandomb(c2, state, l2);
    mpz_nextprime(p1, c1);
    mpz_nextprime(p2, c2);

//    gmp_printf("voici p1: %Zd", p1);
//    gmp_printf("voici p2: %Zd", p2);

    mpz_t n;
    mpz_t m;
    mpz_init(n);
    mpz_init(m);

    /* On met dans n le produit de p1 par p2 */
    mpz_mul(n, p1, p2);

    /* On met dans m le produit de (p1-1) par (p2-1) afin de calculer l'indicatrice d'euler ie le nb d'entiers naturels <=n qui lui sont premiers*/
    mpz_t a;
    mpz_t b;
    mpz_init(a);
    mpz_init(b);
    mpz_sub_ui(a,p1,(unsigned long int)1);
    mpz_sub_ui(b,p2,(unsigned long int)1);
    mpz_mul(m, a, b);

    mpz_t c;
    mpz_init(c);
    mpz_t pgcd;
    mpz_init_set_ui(pgcd, (unsigned long int)2);
    mpz_t i;
//    gmp_printf("voici m: %Zd \n", m);
//    gmp_printf("voici c1: %Zd \n", c1);
//    gmp_printf("voici c2: %Zd \n", c2);
//    gmp_printf("voici p1: %Zd \n", p1);
//    gmp_printf("voici p2: %Zd \n", p2);
//    gmp_printf("voici n: %Zd \n", n);
    mpz_init_set(i,p1);
    mpz_mul_ui(i, i, (unsigned long int)(time(NULL)*time(NULL)*time(NULL)*time(NULL)));
    while(mpz_cmp_ui(pgcd, (unsigned long int)1)!=0 )
    {
            mpz_add_ui(i, i, 1);
            mpz_gcd(pgcd, m, i);
    }
    mpz_set(c, i);

    ClefPubliqueSetn(clef, n);
    ClefPubliqueSetc(clef, c);
    ClefPubliqueSetm(clef, m);
    //gmp_randclear(state);

    /* Libération des variables */
    mpz_clear(p1);
    mpz_clear(p2);
    mpz_clear(c1);
    mpz_clear(c2);
    mpz_clear(taille1);
    mpz_clear(taille2);
    /* doit on libérer m, n, c ??? sachant que c'est le role de ClefPubliqueLiberer */
    mpz_clear(m);
    mpz_clear(n);
    mpz_clear(c);
    mpz_clear(a);
    mpz_clear(b);
    mpz_clear(pgcd);
    mpz_clear(i);

    return clef;
}


void ClefPubliqueAfficher(const ClefPublique * pClefPublique)
{
    if (pClefPublique==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        gmp_printf("Voici la clef publique: %Zd , %Zd \n", ClefPubliqueGetc2(pClefPublique), ClefPubliqueGetn2(pClefPublique));
    }
}


void ClefPubliqueInitialiser(ClefPublique **pClef)
{
    *pClef=(ClefPublique *)malloc(sizeof(ClefPublique));
    mpz_init((*pClef)->n);
    mpz_init((*pClef)->c);
    mpz_init((*pClef)->m);
}


mpz_ptr ClefPubliqueGetn(/*const*/ ClefPublique *pClef)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        return pClef->n;
    }
}


const mpz_ptr ClefPubliqueGetn2(const ClefPublique *pClef)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        return (const mpz_ptr)pClef->n;
    }
}


void ClefPubliqueSetn(ClefPublique *pClef, const mpz_t n1)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_set(pClef->n,n1);
    }
}


void ClefPubliqueStringSetn(ClefPublique *pClef, const char * n1)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_set_str(pClef->n, n1, 10);
    }
}


mpz_ptr ClefPubliqueGetc(/*const*/ ClefPublique *pClef)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        return pClef->c;
    }
}


const mpz_ptr ClefPubliqueGetc2(const ClefPublique *pClef)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        return (const mpz_ptr)pClef->c;
    }
}


void ClefPubliqueSetc(ClefPublique *pClef, const mpz_t c1)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_set(pClef->c,c1);
    }
}


void ClefPubliqueStringSetc(ClefPublique *pClef, const char * c1)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_set_str(pClef->c, c1, 10);
    }
}


mpz_ptr ClefPubliqueGetm(/*const*/ ClefPublique *pClef)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        return pClef->m;
    }
}


void ClefPubliqueSetm(ClefPublique *pClef, const mpz_t m1)
{
    if (pClef==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_set(pClef->m,m1);
    }
}


void ClefPubliqueLiberer(ClefPublique * pClefPublique)
{
    if (pClefPublique==NULL)
    {
        printf("La clef publique n'a pas été alloué \n");
        exit(-1);
    }
    else
    {
        mpz_clear(ClefPubliqueGetn(pClefPublique));
        mpz_clear(ClefPubliqueGetc(pClefPublique));
        mpz_clear(ClefPubliqueGetm(pClefPublique));
        free(pClefPublique);
        pClefPublique=NULL;
    }
}


void testRegressionClefPublique()
{
    printf("test regression ClefPublique \n");
    mpz_t a;
    mpz_t b;
    mpz_t c;

    ClefPublique *clef;
    ClefPubliqueInitialiser(&clef);
    mpz_init_set_ui(a, 54454);
    mpz_init_set_ui(b, 454);
    mpz_init_set_ui(c, 333);
    ClefPubliqueSetn(clef, a);
    ClefPubliqueSetc(clef, b);
    ClefPubliqueSetm(clef, c);
    ClefPubliqueAfficher(clef);
    ClefPublique *clef2;
    clef2=ClefPubliqueGenerer();
    ClefPubliqueAfficher(clef2);

    ClefPubliqueLiberer(clef);
    ClefPubliqueLiberer(clef2);

    mpz_clear(a);
    mpz_clear(b);
    mpz_clear(c);
}
